using System;
using System.Collections;
using System.Collections.Generic;
using System.Timers;
using ImageEffects;
using LogSystem;
using NodeCanvas.Framework;
using UnityEngine;
using Yoozoo.Core.Common;
using Yoozoo.Mars.Got;
using Random = UnityEngine.Random;

namespace Yoozoo.Gameplay.Liberty.AI
{
    public class LibertyCarBirthManager : 
        QualityListenerMono<LibertyCarBirthManager.CarCountQualitySetting>
    {

        [Serializable]
        public class CarCountQualitySetting : QualitySetting
        {
            public int carCount;
            public int beginVanishCarCount;
            public float vanishRadius;
        }

        public SceneTransformDetector carBirthPointDetector;
        public float carRefreshInnerRadius = 80;
        
        public int carCountLimited = 10;

        public int beginVanishCarCount = 5; // 车辆大于这个才开始自动删除
        
        public float vanishRadius = 150;

        public float innerReverseSize = 50;
        public float outerReverseSize = 25;
        
        private Bounds _innerGenerateBounds;
        private Bounds _outerGenerateBounds;
        
        public LayerMask checkLayerMask;

        [Range(0,100)][Header("生成前方车辆的概率")]
        public float frontProbability = 70;
        [Range(0,100)][Header("生成对立行驶车辆的概率")]
        public float opposeProbability = 30;
        
        private bool _carShowStatus = true;

        public List<CarBirthData> carBirthDataList = new List<CarBirthData>(50);
        private List<CarBirthData> _createCarBirthDataList = new List<CarBirthData>(50);

        public Dictionary<int, CarEntity> carEntities = new Dictionary<int, CarEntity>(30);

        public override void ChangeQualitySetting(CarCountQualitySetting qualitySetting)
        {
            carCountLimited = qualitySetting.carCount;
            vanishRadius = qualitySetting.vanishRadius;
        }

        public LightController lightController;
        
        [Header("用于调试的生成数据")]
        public CarBirthData debugBirthData;

        private float _generateCheckTime;
        [Range(0.01f,3f)]
        public float generateCheckTime = 1;
        [Range(0.01f,10f)][Header("同一个生成点生成车辆的最小间隔")]
        public float createIntervalTime = 3f;
        
        private float vanishCheckTime = 0;
        private List<int> vanishList = new List<int>(10);

#if UNITY_EDITOR
        
        void OnDrawGizmos()
        {
            _innerGenerateBounds.DrawBounds(Color.red);
            _outerGenerateBounds.DrawBounds(Color.green);
        }
#endif
        
        private void Update()
        {
            if (!LibertySceneManager.instance)
            {
                return;
            }

            if (!_carShowStatus)
            {
                return;
            }
            
            carBirthPointDetector = (SceneTransformDetector)LibertySceneManager.instance.carBirthPointDetector;
            if (carBirthPointDetector == null)
            {
                return;
            }
            
            Vector3 s = carBirthPointDetector.m_Bounds.size;
            s.x -= innerReverseSize * 2;
            s.z -= innerReverseSize * 2;
                
            _innerGenerateBounds = new Bounds(carBirthPointDetector.m_Bounds.center, s);
                
            Vector3 s1 = carBirthPointDetector.m_Bounds.size;
            s1.x -= outerReverseSize * 2;
            s1.z -= outerReverseSize * 2;
            _outerGenerateBounds = new Bounds(carBirthPointDetector.m_Bounds.center, s1);
            
            _generateCheckTime += Time.deltaTime;
            if (_generateCheckTime > generateCheckTime)
            {
                _generateCheckTime = 0;
                
                if (carBirthDataList.Count > 0)
                {
                    Vector3 pVelocity = LibertyAIUtils.PlayerController.Velocity;
                    Vector3 pPos = LibertyAIUtils.PlayerController.Position;
                    
                    foreach (var birthData in carBirthDataList)
                    {
                        if (_outerGenerateBounds.Contains(birthData.position) && 
                            !_innerGenerateBounds.Contains(birthData.position))
                        {
                            birthData.creatable = true;
                            //TODO: 这里最好处理一下路线方向，让同向的车在后面生成，逆向的车在前方生成
                            // 根据生成车辆的方向、与玩家的前后关系来决定车辆生成的概率
                            // 位置方向
                            bool isFront = Vector3.Dot(pVelocity, (birthData.position - pPos).normalized) > 0;
                            // 行驶方向
                            bool isOppose = Vector3.Angle(birthData.forward, pVelocity) > 135;

                            birthData.isFront = isFront;
                            birthData.isOppose = isOppose;
                        }
                        else
                        {
                            birthData.creatable = false;
                        }
                    }

                    bool front = Random.Range(0, 100) < frontProbability;
                    bool oppose = Random.Range(0, 100) < opposeProbability;
                    _createCarBirthDataList.Clear();
                    foreach (var birthData in carBirthDataList)
                    {
                        if (birthData.creatable && (Time.time - birthData.lastGenerateTime) > createIntervalTime)
                        {
                            if (birthData.isFront == front && birthData.isOppose == oppose)
                            {
                                _createCarBirthDataList.Add(birthData);
                            }
                        }
                    }

                    if (_createCarBirthDataList.Count > 0)
                    {
                        int idx = Random.Range(0, _createCarBirthDataList.Count);
                        var bData = _createCarBirthDataList[idx];
                        bData.lastGenerateTime = Time.time;
                        AddCar(bData);
                    }
                    
                }

            }

            vanishCheckTime += Time.deltaTime;
            if (vanishCheckTime > 1f && 
                carEntities.Count > beginVanishCarCount) // 间隔调用调用一次车辆的隐藏检测
            {
                vanishCheckTime = 0;
                vanishList.Clear();
                if (LibertyAIUtils.PlayerController == null) return;
                
                Vector3 center = carBirthPointDetector.m_Bounds.center;
                center.y = 0;
                
                int vc = 0;
                foreach (var carSeekerPair in carEntities)
                {
                    if ((carSeekerPair.Value.data.carStatus & CarStatus.PlayerControl) > 0)
                    {
                        continue;
                    }

                    if (carSeekerPair.Value.data.carStyle == CarStyle.Static) // 场景中静态物体跟随场景范围销毁
                    {
                        continue;
                    }
                    
                    Vector3 aiPos = carSeekerPair.Value.position;
                    aiPos.y = 0;
                    if (Vector3.Distance(aiPos,center) > vanishRadius)
                    {
                        vanishList.Add(carSeekerPair.Key);
                        vc++;
                        if (vc > 3) // 每次最多移除 3 个
                        {
                            break;
                        }
                    }
                }
            
                foreach (var i in vanishList)
                {
                    Debug.Log(LogModule.LibertyScene,$"自动移除动态车辆：{i}");
                    RemoveCar(i);
                }
            }
        }

        private float _lastUpdateAiTime;
        public float splineModeRadius = 20f;
        
        private void FixedUpdate()
        {
            if (!LibertySceneManager.instance)
            {
                return;
            }

            if (!_carShowStatus)
            {
                return;
            }
            
            if (Time.time - _lastUpdateAiTime > 0.3f)
            {
                UpdateCarAIMode();
                _lastUpdateAiTime = Time.time;
            }
        }

        private void UpdateCarAIMode()
        {
            if ( LibertyAIUtils.PlayerController == null)
            {
                return;
            }
            Vector3 pPos = LibertyAIUtils.PlayerController.Position;
            var enumerator = carEntities.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var carEntity = enumerator.Current.Value;
                if (carEntity != null)
                {
                    Vector3 relativeVector = carEntity.position - pPos;
                    if ((relativeVector - carEntity.data.switchAiModeVector).magnitude > 5)
                    {
                        float distance = relativeVector.magnitude;
                        int lod = 0;
                        if (distance > carEntity.vehicleLodComponent.lod1Distance)
                        {
                            lod = 1;
                        }

                        if (distance > carEntity.vehicleLodComponent.lod2Distance)
                        {
                            lod = 2;
                        }
                        carEntity.vehicleLodComponent.LOD = lod;
                        carEntity.vehicleAI.LOD = lod;
                        
                        if (distance < splineModeRadius)
                        {
                            if (carEntity.vehicleAI.AIMode == VehicleAI.VehicleAIMode.Curve)
                            {
                                carEntity.vehicleAI.EnterSplineMode();
                            }
                        }
                        else
                        {
                            if (carEntity.vehicleAI.AIMode == VehicleAI.VehicleAIMode.Spline)
                            {
                                carEntity.vehicleAI.EnterCurveMode();
                            }
                        }
                        
                        carEntity.data.switchAiModeVector = relativeVector;
                    }
                }
            }
            enumerator.Dispose();
        }
        
        public void AddCarBirthData(CarBirthData birthData)
        {
            carBirthDataList.Add(birthData);
            //UnityEngine.Debug.LogError(birthData.position);
            
            // TODO DEBUG
            //AddCar(birthData);
        }

        public void RemoveCarBirthData(int uId)
        {
            for (int i = 0; i < carBirthDataList.Count; i++)
            {
                if (carBirthDataList[i].uniqueId == uId)
                {
                    carBirthDataList.RemoveAt(i);
                    break;
                }
            }
        }

        private int _carUniqueId = 20000;
        
        public bool AddCar(CarBirthData birthData)
        {
            if (!_carShowStatus && !birthData.ignoreLimit)
            {
                return false;
            }
            
            if (carEntities.Count >= carCountLimited && !birthData.ignoreLimit)
            {
                return false;
            }

            // DEBUG
            birthData.checkCenter = new Vector3(0, 0.78f,0);
            birthData.checkSize = new Vector3(3, 1.37f,6.5f);
            if (!birthData.ignoreLimit)
            {
                // 物理检测有没有其它刚体或角色控制器在生成范围之内
                if (birthData.checkSize.magnitude > 0.1)
                {
                    var colliders = Physics.OverlapBox(
                        birthData.checkCenter + birthData.position,
                        birthData.checkSize,
                        Quaternion.LookRotation(birthData.forward),
                        checkLayerMask);
                    if (colliders.Length > 0)
                    {
                        return false;
                    }
                }
            }
            var pathData = LibertyAIUtils.TrafficManager.PathManager.GetPath(birthData.pathId, PathType.Car);
            
            if (pathData!=null)
            {

                PathPointData point =
                    LibertyAIUtils.TrafficManager.PathManager.GetPathPoint(birthData.pathId, birthData.pathPointIndex);
         
              
                var carEntity = AddCarPure(birthData);
                if (carEntity == null)
                {
                    return false;
                }
                //TODO:这里生成点和point.position不一致,先用路径的点
                carEntity.carController.setPosition(point.position);
                carEntity.carController.setRotation(Quaternion.LookRotation(birthData.forward));
                carEntity.carController.reset(true);
                carEntity.carController.immobilize(true);
                carEntity.SetAIParameters();
                carEntity.vehicleAI.speedStrategy =
                    (VehicleAI.VehicleSpeedStrategy.Const | VehicleAI.VehicleSpeedStrategy.HandBrake);
                GraphOwner graphOwner = carEntity.gameObject.GetComponent<GraphOwner>();
                Blackboard blackboard = carEntity.gameObject.GetComponent<Blackboard>();
                blackboard.SetVariableValue("CarEntity", carEntity);
                graphOwner.StartBehaviour();
                carEntity.InteriorComponent.HideInteriors();
                return true;
            }
            return false;
        }

        public CarEntity AddCarPure(CarBirthData birthData)
        {
            LoadCar(_carUniqueId, birthData.carModelId, birthData.random, out var car);
            if (car == null)
            {
                return null;
            }
            //car.gameObject.SetActive(false);

            
            CarEntity carEntity = car.GetComponent<CarEntity>();
            carEntity.SetAIParameters();
            carEntity.vehicleAI.speedStrategy =
                (VehicleAI.VehicleSpeedStrategy.Const | VehicleAI.VehicleSpeedStrategy.HandBrake);
            // car.transform.position = birthData.position;
            // car.transform.forward = birthData.forward;
            carEntity.carController.setPosition(birthData.position);
            carEntity.carController.setRotation(Quaternion.LookRotation(birthData.forward));
            // 关闭车辆NavMeshCut
            if (carEntity.navmeshCut)
            {
                carEntity.navmeshCut.enabled = false;
            }
                
            carEntity.id = _carUniqueId;
            carEntity.data = new CarData()
            {
                uniqueId = _carUniqueId,
                health =  100,
                carStyle = CarStyle.PathFollow,
                carStatus = CarStatus.PathControl,
                pathId = birthData.pathId,
                driveNpcId = birthData.driveNpcId,
            };
            birthData.uniqueId = _carUniqueId;
            if (carEntity.InteriorComponent.enabled)
            {
                carEntity.InteriorComponent.HideInteriors();
            }
            carEntities.Add(_carUniqueId,carEntity);
            _carUniqueId++;
            return carEntity;
        }

        // public GameObject AddStaticCar(int carModelId, Vector3 position,Vector3 forward)
        // {
        //     CarBirthData birthData = new CarBirthData();
        //     birthData.random = carModelId == -1;
        //     birthData.carModelId = carModelId;
        //     birthData.driveNpcId = 0;
        //     birthData.position = position;
        //     birthData.forward = forward;
        //     
        //     LoadCar(_carUniqueId, birthData.carModelId, birthData.random, out var car);
        //     if (car == null)
        //     {
        //         return null;
        //     }
        //     car.transform.position = birthData.position;
        //     car.transform.forward = birthData.forward;
        //     CarEntity carEntity = car.GetComponent<CarEntity>();
        // }
        
        public bool RemoveCar(int uniqueId)
        {
            carEntities.TryGetValue(uniqueId, out CarEntity carEntity);
            
            var npcManager = LibertyManager.GetInstance("LibertyManager").NpcManager;
            if (carEntity)
            {
                var npcBirthManager = LibertyAIUtils.AIManager.NpcBirthManager;
                if (carEntity.npcLeft)
                {
                    // 车上的主角不能销毁
                    if (carEntity.npcLeft.data.uniqueId != -1)
                    {
                        var entityViewer = carEntity.npcLeft.viewer.transform.parent;
                        entityViewer.parent = carEntity.transform;
                        npcBirthManager.RemoveNpc(carEntity.npcLeft.data.uniqueId);
                    }
                }

                if (carEntity.npcRight)
                {
                    var entityViewer = carEntity.npcRight.viewer.transform.parent;
                    entityViewer.parent = carEntity.transform;
                    npcBirthManager.RemoveNpc(carEntity.npcRight.data.uniqueId);
                }
                carEntity.data.Reset();
                carEntity.vehicleAI.OnRevert();
                carEntities.Remove(uniqueId);
                npcManager.RemoveCar(uniqueId);
                return true;
            }
            return false;
        }
        
        private int LoadCar(int uniqueId,int carId, bool random, out GameObject v)
        {
            var npcManager = LibertyManager.GetInstance("LibertyManager").NpcManager;
            int nId = npcManager.AddCar(carId, random, uniqueId);
            v = null;
            if (nId >= 0)
                v = npcManager.GetCar(uniqueId);
            return nId;
        }

        public CarEntity GetCarEntity(int carId)
        {
            if (carEntities.TryGetValue(carId,out var c))
            {
                return c;
            }

            return null;
        }

        public CarEntity GetCarEntity(Collider col)
        {
            if (carEntities!=null)
            {
                foreach (var carEntity in carEntities)
                {
                    if (carEntity.Value.collider == col)
                    {
                        return carEntity.Value;
                    }
                }
            }
            return null;
        }
        
        public void Clear()
        {
            var npcManager = LibertyManager.GetInstance("LibertyManager").NpcManager;
            foreach (var carEntity in carEntities)
            {
                if (carEntity.Value && carEntity.Value.gameObject)
                {
                    npcManager.RemoveCar(carEntity.Key);
                }
            }
            
            carEntities.Clear();
        }

        public void EnableAllCar(bool excludePlayerCar)
        {
            if (carEntities != null)
            {
                foreach (var carEntity in carEntities)
                {
                    if (carEntity.Value && carEntity.Value.gameObject)
                    {
                        if (excludePlayerCar)
                        {
                            if ((carEntity.Value.data.carStatus & CarStatus.PlayerControl) == 0)
                            {
                                carEntity.Value.EnableVehicle();
                            }
                        }
                        else
                        {
                            carEntity.Value.EnableVehicle();
                        }
                    }
                }
            }

            _carShowStatus = true;
        }

        public void DisableAllCar(bool excludePlayerCar)
        {
            if (carEntities != null)
            {
                foreach (var carEntity in carEntities)
                {
                    if (carEntity.Value && carEntity.Value.gameObject)
                    {
                        if (excludePlayerCar)
                        {
                            if ((carEntity.Value.data.carStatus & CarStatus.PlayerControl) == 0)
                            {
                                carEntity.Value.DisableVehicle();
                            }
                        }
                        else
                        {
                            carEntity.Value.DisableVehicle();
                        }
                    }
                }
            }
            
            _carShowStatus = false;
        }
        
        
    }
}